﻿using MQTTnet;
using MQTTnet.Protocol;
using MQTTnet.Server;
using MqttServerTest.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;

namespace MqttServerTest
{
    internal class MyServer
    {
        private MqttServer _mqttServer = null;
        private const int _point = 1883;
        private const string _userName = "huawow";
        private const string _passWord = "mqtttest";

        /// <summary>
        /// 证书的密码
        /// </summary>
        private const string _pwd = "huawowcloud";

        //static string uuid = "4A950F17-C665273B-EDED4D3C-BCF7B6AC";
        static string uuid = "B4072849-FBC11BF1-18C6CAB9-87A12C84";

        public static readonly JsonSerializerOptions _op = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            PropertyNameCaseInsensitive = true,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        };

        public async Task StartAsync()
        {
            //读取CA证书
            //_ca = new X509Certificate2(Path.Combine(_path, "ca.pem"));
            //X509Certificate2 _ca = new X509Certificate2(@"\HW\certs\server\1\ca.pem");

            //读取server证书
            //X509Certificate2 _certificate = new X509Certificate2(@"\HW\certs\server\1\server.pfx", _pwd, X509KeyStorageFlags.Exportable);
            //_certificate = new X509Certificate2(Path.Combine(_path,"server.pfx"), _pwd, X509KeyStorageFlags.Exportable);

            try
            {
                if (_mqttServer == null)
                {
                    var optionsBuilder = new MqttServerOptionsBuilder()
                        .WithDefaultEndpoint()
                        .WithDefaultEndpointPort(_point)
                    //关闭默认连接
                    /*.WithoutDefaultEndpoint()
                //使用SSL加密连接
                .WithEncryptedEndpoint()
                //设置连接端口
                .WithEncryptedEndpointPort(8883)
                //设置server证书
                .WithEncryptionCertificate(_certificate.Export(X509ContentType.Pfx))
                //设置Tls等级
                .WithEncryptionSslProtocol(SslProtocols.Tls12)
                .WithClientCertificate((sender, cer, chain, sslPolicyErrors) =>
                {
                    try
                    {
                        if (sslPolicyErrors == SslPolicyErrors.None)
                        {
                            return true;
                        }

                        if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
                        {
                            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
                            chain.ChainPolicy.ExtraStore.Add(_ca);
                            chain.Build((X509Certificate2)cer);
                            return chain.ChainElements.Cast<X509ChainElement>().Any(a => a.Certificate.Thumbprint == _ca.Thumbprint);
                        }
                    }
                    catch { }

                    return false;
                })*/
                    ;

                    _mqttServer = new MqttFactory().CreateMqttServer(optionsBuilder.Build());

                    //连接前验证客户端
                    /*_mqttServer.ValidatingConnectionAsync += c =>
                    {

                        var currentUser = _userName;
                        var currentPWD = _passWord;
                        if (currentUser == null || currentPWD == null)
                        {
                            c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;

                        }
                        if (c.Username != currentUser)
                        {
                            c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;

                        }
                        if (c.Password != currentPWD)
                        {
                            c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;

                        }



                        return Task.CompletedTask;
                    };*/



                    //服务器开始后事件
                    _mqttServer.StartedAsync += e => { Console.WriteLine("MQTT服务启动成功!"); return Task.CompletedTask; };
                    //服务器停止后事件
                    _mqttServer.StoppedAsync += e => { Console.WriteLine("MQTT服务停止！"); return Task.CompletedTask; };

                    //客户端连接事件
                    _mqttServer.ClientConnectedAsync += e => { Console.WriteLine($"客户端{e.ClientId}已连接"); ServerPublishMqttTopic("$SYS/broker/clients/connected", "online"); return Task.CompletedTask; };

                    //客户端断开连接事件
                    _mqttServer.ClientDisconnectedAsync += e => { Console.WriteLine($"客户端{e.ClientId}已断开"); return Task.CompletedTask; };

                    //客户端订阅主题事件
                    _mqttServer.ClientSubscribedTopicAsync += e => { Console.WriteLine($"客户端{e.ClientId}已成功订阅[{e.TopicFilter.Topic}]主题"); return Task.CompletedTask; };

                    //客户端取消订阅事件
                    _mqttServer.ClientUnsubscribedTopicAsync += e => { Console.WriteLine($"客户端{e.ClientId}已退订[{e.TopicFilter}]主题"); return Task.CompletedTask; };

                    //客户端发布验证
                    _mqttServer.InterceptingPublishAsync += e =>
                    {
                        var topic = e.ApplicationMessage.Topic;
                        var tp = topic.Split('/');
                        var text = Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment);
                        //var obj = System.Text.Json.JsonSerializer.Deserialize<Status>(text);
                        if (topic.Contains("device/register"))
                        {
                            uuid = tp[^1];
                        }
                        else if (topic.EndsWith("firmware/set"))
                        {
                            var obj = System.Text.Json.JsonSerializer.Deserialize<Status>(text);
                            _ = FirmwareReplyAsync(tp[2], obj.MessageId);
                        }
                        if (topic.EndsWith("sensor/data_reply"))
                        {
                            var obj = System.Text.Json.JsonSerializer.Deserialize<SensorData>(text,_op);
                            var dt=Helper.TimeStampToDateTime(obj.Timestamp);
                            Console.Write($"时间：{dt}\t");
                        }

                        Console.WriteLine($"[{DateTime.Now}]-客户端[{e.ClientId}]>> 主题：{e.ApplicationMessage.Topic} 负荷：{Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment)} Qos：{e.ApplicationMessage.QualityOfServiceLevel} 保留：{e.ApplicationMessage.Retain}");
                        e.ProcessPublish = true;
                        return Task.CompletedTask;
                    };

                    await _mqttServer.StartAsync();
                    Console.WriteLine("MQTT Server is started");
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine($"MQTT Server start fail.>{ex.Message}");
            }

            Console.Title = "Server";

            Loop();
        }

        private void Loop()
        {
            try
            {
                Console.WriteLine("请选择运行模式：");
                Console.WriteLine("0：退出程序");
                Console.WriteLine("1：获得MQTT版本信息");
                Console.WriteLine("2：获取设备AP");
                Console.WriteLine("3：写入寄存器");
                Console.WriteLine("4：获得设备MESH状态信息");
                Console.WriteLine("5：设置设备AP");
                Console.WriteLine("6：获取设备DHCP");
                Console.WriteLine("7：设置设备DHCP");
                Console.WriteLine("8：获取设备RIP");
                Console.WriteLine("9：设置设备RIP");
                Console.WriteLine("10：获取设备VLAN");
                Console.WriteLine("11：设置设备VLAN");
                Console.WriteLine("12：获取设备地址转换");
                Console.WriteLine("13：设置设备地址转换");
                Console.WriteLine("14：获取设备虚拟服务器");
                Console.WriteLine("15：设置设备虚拟服务器");
                Console.WriteLine("16：获取设备访问控制列表");
                Console.WriteLine("17：设置设备访问控制列表");
                Console.WriteLine("18：设置设备MESH");
                Console.WriteLine("19：获取设备接口状态");
                Console.WriteLine("20：获取设备WIFI客户端状态");
                Console.WriteLine("21：设备重启");
                Console.WriteLine("22：升级");
                Console.WriteLine("23：获取GPS定位");
                Console.WriteLine("24：传感器离线数据召测");

                string topic = null;

                while (!string.IsNullOrEmpty(topic = Console.ReadLine()))
                {
                    switch (topic)
                    {
                        case "0":
                            return;
                        case "1"://获取MQTT版本
                            //ServerPublishMqttTopic("hello/world", $"这是一个测试ss：{DateTime.Now}");
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/version/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "2"://获取设备AP                            
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/ap/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "3"://写入寄存器
                            {
                                RegistersR registersR = new RegistersR();
                                registersR.Port = "com1";
                                registersR.SensorAddr = 1;
                                registersR.RegisterList = new RegisterR[2] { new RegisterR(), new RegisterR() };
                                registersR.RegisterList[0].Code = 6;
                                registersR.RegisterList[0].Addr = 258;
                                registersR.RegisterList[0].Value = 20;
                                registersR.RegisterList[1].Code = 6;
                                registersR.RegisterList[1].Addr = 259;
                                registersR.RegisterList[1].Value = 20;
                                ServerPublishMqttTopic($"huawow/server/A63508BE-C809549F-78031BD0-F182E118/thing/event/sensor/write", JsonConvert.SerializeObject(registersR));
                                break;
                            }
                        case "4"://获得MESH状态
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/mesh/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "5"://设置AP
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/ap/set", JsonConvert.SerializeObject(new SetAP()));
                            break;
                        case "6"://获取设备DHCP
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/dhcp/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "7"://设置设备DHCP
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/dhcp/set", JsonConvert.SerializeObject(new SetDHCP()));
                            break;
                        case "8"://获取设备RIP
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/rip/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "9"://设置设备RIP
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/rip/set", JsonConvert.SerializeObject(new SetRIP()));
                            break;
                        case "10"://获取设备VLAN
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/vlan/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "11"://设置设备VLAN
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/vlan/set", JsonConvert.SerializeObject(new SetVlan()));
                            break;
                        case "12"://获取设备地址转换
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/snat/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "13"://设置设备地址转换
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/snat/set", JsonConvert.SerializeObject(new SetSnat()));
                            break;
                        case "14"://获取设备虚拟服务器
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/dnat/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "15"://设置设备虚拟服务器
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/dnat/set", JsonConvert.SerializeObject(new SetDNat()));
                            break;
                        case "16"://获取访问控制列表
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/acl/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "17"://设置设备访问控制列表
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/acl/set", JsonConvert.SerializeObject(new SetACL()));
                            break;
                        case "18"://设置MESH
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/mesh/set", JsonConvert.SerializeObject(new SetMESH()));
                            break;
                        case "19"://获取设备接口状态
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/interface/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "20"://获取WIFI客户端状态
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/wifi/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "21"://设备重启
                            {
                                var act = new Model.Action();
                                Console.Write("是否重启(y/n)：");
                                string re = Console.ReadLine();
                                if (re == "y")
                                {
                                    act.Reboot = "true";
                                }
                                Console.Write("是否保存(y/n)：");
                                string sa = Console.ReadLine();
                                if (sa == "y")
                                {
                                    act.Save = "true";
                                }
                                ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/device/action", JsonConvert.SerializeObject(act));
                                break;
                            }
                        case "22"://升级
                            {
                                FTPUp fTPUp = new FTPUp
                                {
                                    Sha256sum = ComputeFileSHA256.ComputeFiel("d:/hw1570g-a_6.2.3.bin")
                                    //sha256sum = ComputeFileSHA256.ComputeFiel("d:/hw1570l-r.bin")
                                };
                                ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/firmware/set", JsonConvert.SerializeObject(fTPUp));
                                break;
                            }
                        case "23"://获取GPS定位
                            ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/gps/get", JsonConvert.SerializeObject(new Status()));
                            break;
                        case "24"://传感器离线数据召测
                            {
                                SensorCall sensorCall = new();
                                Console.WriteLine("输入开始时间(yyyy-MM-dd HH:mm:ss):");
                                var start=Console.ReadLine();
                                sensorCall.Start=start;

                                Console.WriteLine("输入结束时间(yyyy-MM-dd HH:mm:ss):");
                                var end=Console.ReadLine();
                                sensorCall.End=end;

                                Console.WriteLine("是否删除数据:y-是，n-否");
                                var isDel = Console.ReadLine();
                                if (isDel == "y" || isDel == "y")
                                {
                                    sensorCall.IsDel = "true";
                                }
                                else
                                {
                                    sensorCall.IsDel = "false";
                                }
                                ServerPublishMqttTopic($"huawow/server/{uuid}/thing/service/sensor/call", JsonConvert.SerializeObject(sensorCall));
                                break;
                            }
                        default:
                            Console.WriteLine("请输入正确的指令");
                            break;
                    }
                    Console.WriteLine("请选择运行模式：");
                    Console.WriteLine("0：退出程序");
                    Console.WriteLine("1：获得MQTT版本信息");
                    Console.WriteLine("2：获取设备AP");
                    Console.WriteLine("3：写入寄存器");
                    Console.WriteLine("4：获得设备MESH状态信息");
                    Console.WriteLine("5：设置设备AP");
                    Console.WriteLine("6：获取设备DHCP");
                    Console.WriteLine("7：设置设备DHCP");
                    Console.WriteLine("8：获取设备RIP");
                    Console.WriteLine("9：设置设备RIP");
                    Console.WriteLine("10：获取设备VLAN");
                    Console.WriteLine("11：设置设备VLAN");
                    Console.WriteLine("12：获取设备地址转换");
                    Console.WriteLine("13：设置设备地址转换");
                    Console.WriteLine("14：获取设备虚拟服务器");
                    Console.WriteLine("15：设置设备虚拟服务器");
                    Console.WriteLine("16：获取设备访问控制列表");
                    Console.WriteLine("17：设置设备访问控制列表");
                    Console.WriteLine("18：设置设备MESH");
                    Console.WriteLine("19：获取设备接口状态");
                    Console.WriteLine("20：获取设备WIFI客户端状态");
                    Console.WriteLine("21：设备重启");
                    Console.WriteLine("22：升级");
                    Console.WriteLine("23：获取GPS定位");
                    Console.WriteLine("24：传感器离线数据召测");

                }
            }
            catch (Exception ex)
            {

                Console.WriteLine($"{ex.Message}");
            }
        }

        public async void ServerPublishMqttTopic(string topic, string payload)
        {
            var message = new MqttApplicationMessageBuilder()
                .WithTopic(topic).WithPayload(payload)
                .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
                .Build();
            await _mqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(message)
            {
                SenderClientId = "Server"
            });
            //Console.WriteLine("MQTT Broker发布主题[{0}]成功！=>{1}", topic,payload);
        }

        public async Task StopAsync()
        {
            if (_mqttServer == null)
            {
                return;
            }

            try
            {
                await _mqttServer?.StopAsync();
                _mqttServer = null;
                Console.WriteLine("MQTT Server is Stoped");

            }
            catch (Exception ex)
            {

                Console.WriteLine($"MQTT Server stop fail.>{ex.Message}");
            }
        }

        /// <summary>
        /// 获取客户端列表
        /// </summary>
        /// <returns>客户端列表</returns>
        public Task<IList<MqttClientStatus>> GetClientStatusAsync()
        {
            return _mqttServer.GetClientsAsync();
        }


        public async Task FirmwareReplyAsync(string uid, long id)
        {
            await Task.Delay(1000 * 60);
            Status status = new Status();
            status.MessageId = id;
            ServerPublishMqttTopic($"huawow/device/{uid}/thing/service/firmware/set_reply", JsonConvert.SerializeObject(status));

        }

    }
}